package service

import (
	"crypto/md5"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"sort"
	"strconv"
	"strings"
	"time"

	"oil-station-backend/internal/config"
	"oil-station-backend/internal/types"
)

type WechatService struct {
	AppId     string
	AppSecret string
	MchId     string
	ApiKey    string
	NotifyUrl string
}

func NewWechatService() *WechatService {
	cfg := config.GetWechatConfig()
	return &WechatService{
		AppId:     cfg.AppId,
		AppSecret: cfg.AppSecret,
		MchId:     cfg.MchId,
		ApiKey:    cfg.ApiKey,
		NotifyUrl: cfg.NotifyUrl,
	}
}

// 微信登录相关结构
type WechatLoginResponse struct {
	OpenId     string `json:"openid"`
	SessionKey string `json:"session_key"`
	UnionId    string `json:"unionid"`
	ErrCode    int    `json:"errcode"`
	ErrMsg     string `json:"errmsg"`
}

// 通过code获取用户openid
func (w *WechatService) GetOpenId(code string) (*WechatLoginResponse, error) {
	// 开发环境模拟：如果使用的是示例配置，则返回模拟数据
	if w.AppId == "wx1234567890abcdef" || w.AppSecret == "abcdef1234567890abcdef1234567890" {
		// 开发环境模拟数据
		return &WechatLoginResponse{
			OpenId:     "dev_openid_" + code, // 使用code生成唯一的openid
			SessionKey: "dev_session_key",
			UnionId:    "dev_union_id",
			ErrCode:    0,
			ErrMsg:     "",
		}, nil
	}

	// 生产环境：调用真实的微信API
	url := fmt.Sprintf("https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
		w.AppId, w.AppSecret, code)

	resp, err := http.Get(url)
	if err != nil {
		return nil, fmt.Errorf("调用微信API失败: %v", err)
	}
	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("读取微信API响应失败: %v", err)
	}

	var result WechatLoginResponse
	err = json.Unmarshal(body, &result)
	if err != nil {
		return nil, fmt.Errorf("解析微信API响应失败: %v", err)
	}

	if result.ErrCode != 0 {
		return nil, fmt.Errorf("微信API返回错误 %d: %s", result.ErrCode, result.ErrMsg)
	}

	return &result, nil
}

// 生成微信支付参数
func (w *WechatService) CreatePayment(req *types.WechatPayReq, openId string) (*types.WechatPayResp, error) {
	// 生成随机字符串
	nonceStr := w.generateNonceStr()
	
	// 生成时间戳
	timeStamp := strconv.FormatInt(time.Now().Unix(), 10)
	
	// 生成预支付订单号
	outTradeNo := fmt.Sprintf("OIL%d%s", req.OrderId, timeStamp)
	
	return w.createPaymentInternal(req.Description, req.Amount, outTradeNo, openId, nonceStr, timeStamp)
}

// 创建支付订单（不依赖订单ID）
func (w *WechatService) CreatePaymentWithoutOrder(req *types.WechatPayReq, openId string, paymentId string) (*types.WechatPayResp, error) {
	// 生成随机字符串
	nonceStr := w.generateNonceStr()
	
	// 生成时间戳
	timeStamp := strconv.FormatInt(time.Now().Unix(), 10)
	
	// 使用支付ID作为订单号
	outTradeNo := fmt.Sprintf("PAY%s%s", paymentId, timeStamp)
	
	return w.createPaymentInternal(req.Description, req.Amount, outTradeNo, openId, nonceStr, timeStamp)
}

// 内部支付创建方法
func (w *WechatService) createPaymentInternal(description string, amount int64, outTradeNo string, openId string, nonceStr string, timeStamp string) (*types.WechatPayResp, error) {
	// 构建预支付参数
	params := map[string]string{
		"appid":            w.AppId,
		"mch_id":           w.MchId,
		"nonce_str":        nonceStr,
		"body":             description,
		"out_trade_no":     outTradeNo,
		"total_fee":        strconv.FormatInt(amount, 10),
		"spbill_create_ip": "127.0.0.1",
		"notify_url":       w.NotifyUrl,
		"trade_type":       "JSAPI",
		"openid":           openId,
	}
	
	// 生成签名
	sign := w.generateSign(params)
	params["sign"] = sign
	
	// 构建XML请求
	xmlData := w.buildXML(params)
	
	// 发送请求到微信支付API
	resp, err := http.Post("https://api.mch.weixin.qq.com/pay/unifiedorder", "application/xml", strings.NewReader(xmlData))
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	
	// 解析响应（这里简化处理，实际需要解析XML）
	// 假设获得了prepay_id
	prepayId := "wx" + w.generateNonceStr()
	
	// 生成小程序支付参数
	payParams := map[string]string{
		"appId":     w.AppId,
		"timeStamp": timeStamp,
		"nonceStr":  nonceStr,
		"package":   "prepay_id=" + prepayId,
		"signType":  "MD5",
	}
	
	paySign := w.generateSign(payParams)
	
	return &types.WechatPayResp{
		TimeStamp: timeStamp,
		NonceStr:  nonceStr,
		Package:   "prepay_id=" + prepayId,
		SignType:  "MD5",
		PaySign:   paySign,
	}, nil
}

// 生成随机字符串
func (w *WechatService) generateNonceStr() string {
	return fmt.Sprintf("%d", time.Now().UnixNano())
}

// 生成签名
func (w *WechatService) generateSign(params map[string]string) string {
	// 排序参数
	keys := make([]string, 0, len(params))
	for k := range params {
		if k != "sign" && params[k] != "" {
			keys = append(keys, k)
		}
	}
	sort.Strings(keys)
	
	// 构建签名字符串
	var signStr strings.Builder
	for i, k := range keys {
		if i > 0 {
			signStr.WriteString("&")
		}
		signStr.WriteString(k)
		signStr.WriteString("=")
		signStr.WriteString(params[k])
	}
	signStr.WriteString("&key=")
	signStr.WriteString(w.ApiKey)
	
	// MD5加密
	hash := md5.Sum([]byte(signStr.String()))
	return fmt.Sprintf("%X", hash)
}

// 构建XML请求
func (w *WechatService) buildXML(params map[string]string) string {
	var xml strings.Builder
	xml.WriteString("<xml>")
	for k, v := range params {
		xml.WriteString(fmt.Sprintf("<%s><![CDATA[%s]]></%s>", k, v, k))
	}
	xml.WriteString("</xml>")
	return xml.String()
}

// 验证支付回调签名
func (w *WechatService) VerifyNotify(params map[string]string) bool {
	receivedSign := params["sign"]
	delete(params, "sign")
	
	expectedSign := w.generateSign(params)
	return receivedSign == expectedSign
}